查看原文
其他

完全由C编写,高度可移植,超级牛逼的菜单架构!

宋磊锋 芯片之家 2022-05-20

今天给大家推荐一个非常不错的菜单架构,好朋友宋工写的,他把他认为最能拿得出手的东西贡献了出来,是一个挺不错的菜单架构,大家拿到源码,可以自己学习借鉴下。


框架,相对一套完整的程序来说,往往是最重要的,一个好的程序框架,不仅能使代码更加清晰明了,稳定运行,而且可以很方便的扩展功能,非常易于维护。很多大神的经典代码框架,大家都可以欣赏下,之后,完全领悟其中的精髓,融会贯通,用于实际的项目,为社会创造价值。之前分享过两篇,这里重新贴出来一下:

完全由C编写,高度可移植,超级牛逼的软件定时器!
完全由C编写,高度可移植,超级牛逼的按键驱动机制!
这个文章感觉可以叫完全系列了开个玩笑,接下来进入正题。

接下来说一说我这个菜单架构,大家看到后可能觉得眼熟,对,我之前一直想做一个适合自己易用的菜单系统,所以参考了网上所有菜单相关的帖子,提取其中的优点,加入自己的理解,改造出我认为非常好用的菜单架构,现在发出来,并带上讲解,欢迎大家探讨。

首先看一下菜单视频,这个作品是17年参加立创电子设计大赛的,得了个优秀奖。

这个菜单系统会根据定义自动构建菜单层级,超时自动退回主界面,菜单值预览等功能。

0主界面

1日期设置 (设置阳历,农历自动计算)
2时间设置
-----------2.1时间调整
-----------2.2 24小时制
-----------2.3 时间校准 (用于时间隔一段时间自动加减几秒,PSDS3231的精度够了,完全不用校准)
3语音设置
-----------3.1 播报模式 (详细模式,简洁模式)
-----------3.2 播报时段 (设置几点到几点开启语音播报)
-----------3.3 音量
4温度选择 (选择显示的文档来自哪一个传感器,并且在每个传感器里面可以设置各自的补偿)
-----------4.1 DS3231 
-----------4.2 DS18B20 
-----------4.3 SHT30 
5 显示效果 (目前使用的是渐变切换效果,感觉这个最入眼,什么滚动,百叶窗的个人不喜欢,留个接口后面慢慢加进去吧)
6亮度设置
------------6.1 亮度模式 (固定亮度或者自动亮度)
------------6.2 亮度标定 (设置自动亮度时,最高光线和最暗光线对应的亮度值)
------------6.3 环境亮度 (获取环境的最高和最暗光线值)
--------------------------6.3.1 自动学习 (24小时自动采集环境的最高和最暗光线值)
--------------------------6.3.2 手动采集 (手动采集环境的最高和最暗光线值)
--------------------------6.3.3 手动设置 (手动指定)
7 遥控设置
------------7.1遥控开关 (使用完遥控后可在此关闭遥控的响应,这样用遥控控制原设备的时候就不会影响到时钟了)
------------7.2 遥控学习
8 字体设置
------------8.1 字体选择 (选择时钟字体、菜单字体)
------------8.2 字体颜色 (选择时钟颜色、菜单颜色)
9 频谱 (暂时没做,接口留着,后面慢慢加)
-------------9.1颜色设置
-------------9.2 分频设置
-------------9.3 打开频谱
10 授时设置 (DS3231的精度足够,个人感觉不用浪费买个GPS或者网络模块进行授时,不过接口放在这里,可以在这里设置用什么模块授时,什么时候授时)
11 闹钟设置 (6组闹钟,可以单独设置周内的星期几响)
-------------11.1闹钟一
-------------11.2闹钟二
-------------11.3闹钟三
-------------11.4闹钟四
-------------11.5闹钟五
-------------11.6闹钟六
12 屏幕检测 (考虑到LED点阵屏幕会有坏点,所以加了个屏幕检测功能,红-绿--三色循环显示)
13 还原设置
14 版本信息

这个菜单架构支持多级菜单,三级,四级,五级。。。接下来看一下菜单定义方式,汉字部分是菜单要显示的文字,数字部分表示菜单层级关系。0是主界面 ,1,2,3,4。是最顶层菜单,201,202,203是菜单2的下一级菜单,如果要给201时间调整下面再增加一级子菜单,只需要复制一行,把数字这里改成20101就可以了,要删除某一菜单也很简单,如果该菜单是最底层菜单直接删除该行定义就行了,如果有子菜单,可以通过改数字,把下级菜单提到上级。MENU_MODE_QUICKVIEW是我后来加的,意思是显示菜单列表的时候,是否在该行最右边显示菜单内的值,比如:

闹钟一。。。。关
闹钟二。。。。开

这样,就不用点ok键很快就可以看到总开关了,需要设置具体的值的时候再点ok进去设置。另外这个MenuNode结构体后面得再改造一下,现在的结构没有把常量与状态量分开存放,有些浪费RAM,后期改进。

BrotherNode_First、BrotherNode_End、BrotherNode_Prev。。这几个成员也可以直接在数组中定义好,但是这样一来,一个是得开发人员自己去填,容易填错,另外如果菜单加一个或者删一个,那前后的菜单都要改,所以这里直接都设置成NULL,有菜单内核自己去解析并赋值,目前这样我觉得耦合是最低的。

typedef struct _MenuNode
{

    const unsigned char* Title;
    unsigned long int ID: 26;
    unsigned long int Mode: 1;
    unsigned long int Status: 1;
    unsigned long int CurrentItem: 4;
    char* Message_String;
    struct _MenuNode* BrotherNode_First;
    struct _MenuNode* BrotherNode_End;
    struct _MenuNode* BrotherNode_Prev;
    struct _MenuNode* BrotherNode_Next;
    struct _MenuNode* FatherNode;
    struct _MenuNode* SonNode_First;
    void (*SetPageRun) (void* Para);
} MenuNode;
MenuNode MenuNodes[MENU_NODES_COUNT] =
{
    { (const unsigned char*)"主界面"0, MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Main},
    { (const unsigned char*)"日期设置"1,   MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Set_Date},
    { (const unsigned char*)"时间设置"2,   MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"时间调整"201,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Set_Time},
    { (const unsigned char*)"24小时制"202,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Set24Time},
    { (const unsigned char*)"时间校准"203,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetTimeCalibration},
    { (const unsigned char*)"语音设置"3,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"播报模式"301,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetVoiceMode},
    { (const unsigned char*)"播报时间"302,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetVoiceStartEnd},
    { (const unsigned char*)"音量"303,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetVolume},
    { (const unsigned char*)"温度选择"4,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"DS3231"401,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Senser_Ds3231},
    { (const unsigned char*)"DS18B20"402,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Senser_Ds18b20},
    { (const unsigned char*)"SHT30"403,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_Senser_Sht30},
    { (const unsigned char*)"显示效果"5,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"时间参数"501,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_DisplayTimerSet},
    { (const unsigned char*)"页面开关"502,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_DisplayPageEnable},
    { (const unsigned char*)"版式选择"503,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_PageSwitch},
    { (const unsigned char*)"亮度设置"6,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"亮度模式"601,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetBrightnessMode},
    { (const unsigned char*)"亮度标定"602,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetBrightnessCelibration},
    { (const unsigned char*)"环境亮度"603,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"自动采集"60301,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_EnvBightNessLearnAuto},
    { (const unsigned char*)"手动采集"60302,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_BrightnessLearnManuel},
    { (const unsigned char*)"手动设置"60303,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_BrightnessLearnSet},
    { (const unsigned char*)"灵敏度"604,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetBrightness_Sensitivity},
    { (const unsigned char*)"遥控设置"7,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"遥控开关"701,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetRemoteKeyEnable},
    { (const unsigned char*)"遥控学习"702,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_RemoteKeyLearn},
    { (const unsigned char*)"字体设置"8,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"字体选择"801,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetFontType},
    { (const unsigned char*)"字体颜色"802,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetFontColor},
    { (const unsigned char*)"频谱"9,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"颜色设置"901,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"分频设置"902,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"打开频谱"903,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"授时设置"10,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_GUI_Test},
    { (const unsigned char*)"闹钟设置"11,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU},
    { (const unsigned char*)"闹钟一"1101,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"闹钟二"1102,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"闹钟三"1103,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"闹钟四"1104,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"闹钟五"1105,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"闹钟六"1106,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_SetAlarmClock},
    { (const unsigned char*)"屏幕检测"12,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_ScreenLed_Check},
    { (const unsigned char*)"还原设置"13,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_RestoreDefault},
    { (const unsigned char*)"版本信息"14,  MENU_MODE_QUICKVIEW, MENU_STATUS_NORMAL, MENU_PAGE_ITEM_DEFAULT, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, NULL_MENU, &Page_VisionInfo},
};
说完菜单定义,接下来讲解一下每个菜单项点击OK键后的动作吧,可以看到上面每个菜单项的定义的最右边,关联的是该菜单项进入后的界面,有子菜单的菜单项后面都是NULL,菜单内核会自动显示子菜单列表。下面是声音设置界面,通过MenuRunInfo* MenuRunInfos将当前的键值、菜单位置状态传入页面函数,switch结构切换当前要调整的项。根据键值进入相应的分支,界面有改变后,在下面刷新界面。所有的设置页面可以定义到单独的一个文件中。我在Menu_Page.中定义着。

void Page_SetVolume (MenuRunInfo* MenuRunInfos)
{
#define PAGE_ITEM_VOLUME    1

    if (MenuRunInfos->CursorMenu->Mode  == MENU_MODE_QUICKVIEW)
    {
        return;
    }
    else
    {

    }

    switch (MenuRunInfos->CursorMenu->CurrentItem)
    {
        case MENU_PAGE_ITEM_DEFAULT:
            MenuRunInfos->CursorMenu->CurrentItem = PAGE_ITEM_VOLUME;

            if (MySettings.Volume > 10)
            {
                MySettings.Volume = 10;
            }

            MenuRunInfos->CursorMenu->Status = MENU_STATUS_HAS_UPATE;
            break;

        case PAGE_ITEM_VOLUME:
            switch (*MenuRunInfos->KeyCode)
            {
                case BT_KEYCODE_MENU:
                case BT_KEYCODE_MENU_RMET:
                    MenuRunInfos->flg_CurrentPage = MENU_CURRENT_PAGE_SET_LIST;
                    MenuRunInfos->CursorMenu->CurrentItem = MENU_PAGE_ITEM_DEFAULT;
                    MenuIf_ListShow (MenuRunInfos);

                    return;

                case BT_KEYCODE_UP:
                case BT_KEYCODE_UP_RMET:
                    if (MySettings.Volume < 10)
                    {
                        MySettings.Volume++;
                        //FIXME:SLF 2018-05-30 调整音量时播放试听音
                        MenuRunInfos->CursorMenu->Status = MENU_STATUS_HAS_UPATE;
                    }

                    break;

                case BT_KEYCODE_DOWN:
                case BT_KEYCODE_DOWN_RMET:
                    if (MySettings.Volume > 0)
                    {
                        MySettings.Volume--;
                        //FIXME:SLF 2018-05-30 调整音量时播放试听音
                        MenuRunInfos->CursorMenu->Status = MENU_STATUS_HAS_UPATE;
                    }

                    break;

                case BT_KEYCODE_OK:
                case BT_KEYCODE_OK_RMET:

                    break;

                default:
                    break;
            }

            break;
    }

    if (MenuRunInfos->CursorMenu->Status == MENU_STATUS_HAS_UPATE)
    {
        Screen_Printf (00, MySettings.FontCfg.FontType_Menu, SCREEN_COLOR_RED, SCREEN_UPDATE_NORMAL, "音量调整");
        Screen_Printf (160, FontsType_DefaultMix, SCREEN_COLOR_RED, SCREEN_UPDATE_NORMAL, "1-10");

        if (MenuRunInfos->CursorMenu->CurrentItem == PAGE_ITEM_VOLUME)
        {
            MenuRunInfos->CursorMenu->Status = MENU_STATUS_NORMAL;
            Screen_Clear (16402416, SCREEN_COLOR_GREEN, SCREEN_UPDATE_NORMAL);
            Screen_Printf (1640, FontsType_DefaultMix, SCREEN_COLOR_GREEN, SCREEN_UPDATE_NORMAL, "%d", MySettings.Volume);

        }

        Screen_UpdateImmediately (SCREEN_COLOR_ALL);
    }

#undef PAGE_ITEM_VOLUME
}
然后说一下使用,Menu.c文件是菜单内核文件,不需要修改。使用时先调用Menu_NodesInit (void),初始化各项菜单,并自动建立菜单层级关系。Menu_Loop (void)函数周期调用即可。使用KeyCode全局变量 传入键值。Menu_If.c是接口文件,MenuIf_MenuDispatcher函数不怎么需要改, MenuIf_ListShow (MenuRunInfo* MenuRunInfos)函数需要根据自己的显示屏幕改一下。然后就是定义菜单数组和写每一项菜单的页面函数了。传上我的文件,抛砖引玉,欢迎探讨!

程序源码,公众号后台回复菜单架构下载!

往期好文合集

【视觉盛宴】你没见过的电子元器件的另一面!

【视觉盛宴二】长见识了,你见过BGA封装芯片的横截面吗!

【视觉盛宴三】不好意思,这些线材接口的横截面真的没见过

【最强干货】618个3D封装免费分享

【干货第二波】一大波3D封装免费分享

【干货第三波】一套完整STM32F4开发板分享

【收藏】芯片之家精选好文合集

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存